package org.idontknow.prey.loader;

import java.lang.ClassLoader;
import java.util.HashMap;
import java.lang.Class;
import java.io.*;
import java.lang.ClassNotFoundException;
import java.lang.Exception;

import org.idontknow.prey.species.Species;

public class MyClassLoader extends ClassLoader {

  HashMap<String, Class<? extends Species>> cache = new HashMap<String, Class<? extends Species>>(128, .75f);

  @SuppressWarnings("unchecked")
public synchronized Class<? extends Species> loadClass(String className, boolean resolveIt)
    throws ClassNotFoundException {
    Class<? extends Species> result;
    byte[] classData;
    System.out.println("  >>>>>> Load class : " + className);
    result = cache.get(className);
    if(result != null) {
      System.out.println("  >>>>>> returning cached result.");
      return result;
    }
    try{
      result = (Class<? extends Species>) super.findSystemClass(className);
      System.out.println("  >>>>>> returning system class (in CLASSPATH).");
      return result;
    }catch(ClassNotFoundException e) {
      System.out.println("  >>>>>> Not a system class.");
    }
    classData = getClassImpl(className);
    if(classData == null) {
      throw new ClassNotFoundException();
    }
    result = (Class<? extends Species>) defineClass(null, classData, 0, classData.length);
    if(resolveIt) {
      resolveClass(result);
    }
    cache.put(className, result);
    System.out.println("  >>>>>> Returning newly loaded class.\n");
    return result;
  }

  private byte[] getClassImpl(String name) {
    byte[] result = null;
    try{
      FileInputStream fi = new FileInputStream(System.getProperty("user.dir") + File.separator + "classes/org/idontknow/prey/species/" + name + ".class");
      result = new byte[fi.available()];
      fi.read(result);
    }catch(Exception e){
      System.out.println("  >>>>>> Failed to load class implementation.");
    }
    return result;
  }
}
